=begin
  Questo controllore gestisce la registrazione degli utenti nel sito:
   - creazione ed attivazione account
   - recupero password smarrita
   - eliminazione account
   - modifica account
=end

# E' il controller della componente users, e fornisce le azioni per gestire gli utenti.
# La gestione è formata dalle azioni di base, ovvero la creazione, la modifica e la cancellazione,
# e dalle azioni per recuperare la password.
class UsersController < ApplicationController
  # Gli altri controlli sono fatti a mano all'interno delle azioni, con il metodo owner_or_admin
  before_filter :authorize_admin, :only => [:index]
  before_filter :authorize_not_logged, :only => [:new, :register, :new_password_reset, :send_password_reset, :create]
  
  # Indice degli utenti. Accessibile soltanto all'amministratore
  def index
    @users = User.paginate :per_page => 3, :page => params[:page], :order => 'username'
    
    respond_to do |format|
      format.html
      format.xml  { render :xml => @users }
    end
  end
  
  def new
    @user = User.new
    
    respond_to do |format|
      format.html
      format.xml  { render :xml => @user }
    end
  end
  
  # Aggiunge l'utente passato come parametro al database.
  def create
    @user = User.new(params[:user])
    @user.assessment = Assessment.new
    logger.info " *** Dopo users.new: #{@user.password}"
    
    right = false
    
    if @user.save
      # Includo il codice per inviare la mail in un blocco begin-rescue-end (il try catch di java) poiché
      # rails controlla se l'indirizzo di posta è corretto prima di inviare. Se questi non lo è viene generato
      # un errore (da intendere come un'eccezione di java e non come un errore di esso).
      begin
        # Specifico che deve essere inviata la mail per la conferma della registrazione
        UserMailer.deliver_registration_confirmation(@user)
        right = true
      rescue Net::SMTPFatalError => err
        flash.now[:error] = "Hey, questa e-mail non esiste!"
        logger.warn "C'è stato un errore inviando il messaggio a questa e-mail #{@user.mail}:\n\t#{err}"
        # Dal momento in cui la'eccezione viene gestita l'utente è salvato: va cancellato
        @user.destroy
      end
    else
      flash.now[:error] = "Ci sono stati problemi con la tua registrazione."
    end
    
    respond_to do |format|
      if right
        flash[:notice] = "Abbiamo inviato un'e-mail all'indirizzo \"#{@user.mail}\": essa contiene le istruzioni per confermare la registrazione"
        format.html { redirect_to :controller => "general", :action => "index" }
        format.xml  { render :xml => @user, :status => :created, :location => @user }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @user.errors, :status => :unprocessable_entity }
      end
    end
  end
  
  # Recupera l'utente che ha l'id passato come parametro, se l'utente è il proprietario oppure
  # è l'amministratore.
  def edit
    logger.info "UserController, edit, id: #{params[:id]}"
    user = User.find_by_id(params[:id])
    
    respond_to do |format|
      if owner_or_admin(user.username)
        @user = user
        logger.info "Utente: #{@user.username}"
        format.html
        format.xml {head :ok}
      else
        format.html {redirect_to root_path, :status => 401}
        format.xml {head 401}
      end
    end
  end
  
  # Modifica un utente specificato dall'id. Questa azione è consentita soltanto all'utnete proprietario od all'amministratore
  def update
    right = false
    unauthorized = false
    
    if request.put?
      @user = User.find_by_id(params[:id])
      
      msg = "Utente #{@user.username} "
      
      if !@user.blank? && owner_or_admin(@user.username)
        if @user.update_attributes(params[:user])
          flash[:notice] = msg + "modificato con successo"
          right = true
        else
          flash.now[:notice] = msg + "non modificato"
        end
      else
        unauthorized = true
        flash[:warning] = "Non sei autorizzato a fare questo!"
      end
    end
    
    respond_to do |format|
      if right
        format.html {redirect_to :controller => "users", :action => "show", :id => @user.id}
        format.xml { head :ok }
      else
        unless unauthorized
          unless request.put?
            format.html {redirect_to :action => 'edit', :id => params[:id], :status => 405} # Method not allowed
          else
            format.html {render :action => 'edit'}
          end
          format.xml {render :xml => @user.errors, :status => :unprocessable_entity}
        else
          format.html {redirect_to root_path, :status => 401}
          format.xml {head 401}
        end
      end
    end
  end
  
  # Elimina l'utente specificato dall'id. Consentito soltanto all'amministratore ed all'utente proprietario
  def destroy
    right = false
    
    if request.delete?
      user = User.find_by_id(params[:id])
      
      if owner_or_admin(user.username)
        if owner(user.username)
          @user_session.log_out_user!
        end
        user.destroy
        flash[:notice] = 'Utente cancellato con successo.'
        right = true
      else
        flash[:warning] = "Non sei autorizzato a fare questo!"
      end
    end
    
    respond_to do |format|
      if right
        format.html {redirect_to :controller => "general", :action => "index"}
        format.xml { head :ok }
      else
        format.html {redirect_to :controller => "general", :action => "index", :status => 401}
        format.xml {head 401}
      end
    end
  end
  
  # Trova e mette a disposizione della vista l'utente specificato. E' consentito sol al proprietario ed all'amministratore.
  def show
    @user = User.find_by_id(params[:id])
    
    respond_to do |format|
      if !@user.blank? && owner_or_admin(@user.username)
        format.html # show.html.erb
        format.xml  { render :xml => @user }
      else
        flash[:warning] = "Non sei autorizzato a vedere questo utente."
        format.html { redirect_to :controller => "general", :action => "index", :status => 401 }
        format.xml { head :unauthorized } #401
      end
    end
  end
  
  ########## Registrazione dell'utente
  
  
  # Questa azione conferma la registrazione dell'utente specificato dall'id passato come
  # parametro. Se l'id non è valido, oppure l'utente è già attivo, non viene eseguita alcuna operazione.
  # Il link per arrivare a questa azione è nella mail inviata all'utente che l'ha richiesta, nell'azione
  # create.
  def register
    # Controllo che l'utente esiste nel database
    @user = User.find_by_id(params[:id])
    
    # Se l'utente non esiste lo mando ad una pagina in cui lo avviso di questo
    if @user.blank?
      flash[:notice] = "Non hai confermato la registrazione in tempo o non lo hai mai fatto: in entrambi i casi devi rifare il procedimento di registrazione dall'inizio per essere registrato"
    elsif @user.is_active?
      # In questo caso l'utente è giò confermato e segue nuovamente il link
      flash[:notice] = "La tua registrazione &egrave; gi&agrave; stata confermata."
    else
      # Utilizzo l'update attribute per non passare attraverso la validazione. Se usassi save, ci sarebbe la validazione, e dato che password sarebbe vuoto
      # essa non consentirebbe di salvare l'utente. Per saltare la validazione potre chiamare save(false), ma in questo modo sono più sicuro di non fare
      # cazzate
      @user.update_attribute :is_active, true
      
      flash[:notice] = "Grazie per esserti unito a questo gioco. Speriamo ti diverta! Team HTD."
    end
    
    respond_to do |format|
      format.html { redirect_to root_path }
      format.xml { head :ok }
    end
  end
  
  
  ################# Reset della password
  
  
  # Prepara l'attributo mail per la vista associata, che consente di inviare l'e-mail per resettare la password.
  def new_password_reset
    @email = ""
    
    respond_to do |format|
      format.js if request.xhr?
      format.html
      format.xml  { render :xml => @email }
    end
  end
  
  
  
  
  
  # Invia la e-mail all'indirizzo specificato per il reset. Se la mail non è presente nel database oppure
  # non è valida, non succede niente.
  def send_password_reset
    mail = params[:email]
    user = User.find_by_mail(params[:email])
    if !user.blank?
      begin
        UserMailer.deliver_reset_password(user)
        logger.info "E-mail sent to \"#{mail}\" for doing password reset."
        @msg = flash[:notice] = "Ti abbiamo inviato una e-mail con le istruzioni per cambiare la password."
      rescue Net::SMTPFatalError => err
        # L'errore si può verificare nel caso in cui l'indirizzo mail inserito al momento della registrazione
        # è stato eliminato (dismesso ecc.)
        logger.warn "Problema nell'invio della mail per il reset della password: \"#{err}\""
        @msg = flash[:error] = "L'e-mail inserita \"#{mail}\" non &egrave; valida"
      end
    else
      logger.info "Utente con mail \"#{mail}\" non pi&ugrave; nel DB."
      # Questo capita se l'indirizzo non sta più nel database
      @msg = flash[:warning] = "Scusaci, la tua e-mail \"#{mail}\" non &egrave; nel nostro database. L'hai dimenticata??"
    end
    
    respond_to do |format|
      if request.xhr?
        flash[:warning] = flash[:notice] = flash[:error] = nil
        format.js
      else
        format.html {redirect_to root_path}
        format.xml {head :ok}
      end
    end
  end
  
  
  
  
  
  # Completa il reset della password, recuperando l'utente corrispondente alla mail e confrontando il codice di identificazione passato con quello
  # calcolato. Se l'utente non è presente nel database, oppure il codice non corrisponde, non succede niente.
  # Questa azione viene raggiunta dal link sulla mail di reset.
  def insert_new_password
    user = User.find_by_mail(params[:mail])
    right = false
    
    if !user.blank? && user.is_active?
      calculated_password = UserMailer.encrypted_reset_code user.id, user.mail
      logger.info "Password trovate:\n\tMail: #{params[:code]}\n\tCalcolata: #{calculated_password}"
      if calculated_password == params[:code]
        @user_session.log_out_user! # Logout dell'utente loggato.
        @user_session.log_in_user(user)
        flash[:notice] = "#{user.username}, vuoi cambiare la tua password"
        right = true
      else
        flash[:warning] = "Pensiamo che non puoi fare quello che stai cercando di fare. Cosa stai cercando di fare!?"
      end
    else
      flash[:notice] = "Scusaci, utente non trovato o non registrato."
    end
    
    respond_to do |format|
      unless right
        format.html {redirect_to root_path, :status => 401}
        format.xml { head :unauthorized }
      else
        format.html {redirect_to :action => 'edit', :id => user.id}
        format.xml { head :ok }
      end
    end
  end
end